package bean.managed;

import bean.managed.util.JsfUtil;
import bean.session.DepartmentEntityFacade;
import bean.session.InternalMessageEntityFacade;
import bean.session.SystemUserEntityFacade;
import java.util.*;
import entity.DepartmentEntity;
import entity.InternalMessageEntity;
import entity.InternalMessageReceivedEntity;
import entity.SystemUserEntity;
import java.io.*;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.faces.model.SelectItem;
import managedbean.AbstractBacking;
import org.primefaces.event.SelectEvent;
import org.primefaces.event.TabChangeEvent;
import type.MessageType;

@ManagedBean(name = "userMessageController")
@SessionScoped
public class UserMessageController extends AbstractBacking implements Serializable {

    protected InternalMessageEntity current;
    protected String status;
    protected String result;
    protected List<InternalMessageEntity> msg;
    protected InternalMessageEntity selectedMessage;
    protected InternalMessageEntity messageTobeDeleted;
    @EJB
    protected bean.session.InternalMessageEntityFacade ejbFacade;
    @EJB
    protected DepartmentEntityFacade departmentBean;
    @EJB
    protected SystemUserEntityFacade userBean;
    @ManagedProperty(value = "#{messageController}")
    protected MessageController userManagedBean;
    protected HashMap<InternalMessageEntity, InternalMessageReceivedEntity> msgToUserInstance;
    protected int totalUnread;
    protected MessageType messageType;
    protected int tabIndex=1;
    
    private String redirectLink = "/entities/internalMessageEntity/UserMessage.xhtml?faces-redirect=true";
    private String viewLink = "/entities/internalMessageEntity/ViewUserMessage.xhtml?faces-redirect=true";

    public InternalMessageEntity getSelected() {
        if (current == null) {
            current = new InternalMessageEntity();
        }
        return current;
    }
      public String viewInbox() {
      
        System.out.println("Contact View: " + current);
        return "/entities/internalMessageEntity/UserMessage?faces-redirect=true";
    }
    public void populateInbox() {
        if(getCurrentUser()==null)
            return;
        
        current = null;
        messageType = MessageType.UserMessage;
        userManagedBean.isDisplayUserMessageInbox();
        msg = userManagedBean.getUserMessageInbox();
        markMessagesReadUnread();
    }

    public void action(TabChangeEvent event) {
        String folderName = event.getTab().getId();
        System.out.println("Accessing Folder: " + folderName);

        if (folderName.equals("inbox")) {
            populateInbox();
        }

        if (folderName.equals("sent")) {
            current = null;
            userManagedBean.isDisplayUserMessageSent();
            msg = userManagedBean.getUserMessageSent();
        }

        if (folderName.equals("drafts")) {
            current = null;
            userManagedBean.isDisplayUserMessageDraft();
            msg = userManagedBean.getUserMessageDraft();
        }

        setStatus("");
    }

    protected void markMessagesReadUnread() {
        totalUnread = 0;
        if (getCurrentUser() != null) {
            if(msgToUserInstance==null)
                msgToUserInstance = new HashMap<InternalMessageEntity, InternalMessageReceivedEntity>();
            for (InternalMessageReceivedEntity instance : getCurrentUser().getMessagesReceivedInstances()) {
                msgToUserInstance.put(instance.getMsg(), instance);
                if(!instance.read() && instance.getMsg().getMessageType()==messageType)
                    totalUnread++;
            }
            for (InternalMessageEntity m : msg) {
                m.setRead(msgToUserInstance.get(m).read());
            }
        }
    }

    public void deleteMessage() {
    }

    public String messageSelect(SelectEvent event) {
        System.out.println("Message Selected: " + selectedMessage);
        System.out.println("" + (null == (InternalMessageEntity) event.getObject()));
        current = selectedMessage;
        if (isForInbox()) {
            markAsRead();
        }
        return getViewLink();
    }

    public void prepareView() {
        current = getSelectedMessage();
    }

    public String draftSelect(SelectEvent event) {

        System.out.println("Opening Saved Draft: " + selectedMessage);
        System.out.println("" + (null == (InternalMessageEntity) event.getObject()));
        current = selectedMessage;
        tabIndex = 0;
        return getRedirectLink();
    }

    public void statusUpdate(String status) {
        FacesContext context = FacesContext.getCurrentInstance();
        context.addMessage(null, new FacesMessage(status, null));
    }

    protected String create() {
        try {
            setSender();
            current.created(getLoginPerson());
            getFacade().create(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("InternalMessageEntityCreated"));
            return null;
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    protected String update() {
        try {
            if (current.getSentAt() != null) {
                JsfUtil.addErrorMessage(new Exception("Cannot edit sent message."), "Cannot edit sent message.");
                return null;
            }
            setSender();
            current.modified(getLoginPerson());
            getFacade().edit(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("InternalMessageEntityUpdated"));
            return null;
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    private void performDestroy(InternalMessageEntity message) {
        try {
            getFacade().remove(message);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("InternalMessageEntityDeleted"));
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
        }
    }

    public String createOrUpdateUserMessage() {
        current.setMessageType(MessageType.UserMessage);
        if (current.getId() != null) {
            return update();
        } else {
            return create();
        }
    }

    public String createOrUpdateUserMessageAndSend() {
        current.setMessageType(MessageType.UserMessage);
        if (current.getId() != null) {
            return updateAndSend();
        } else {
            return createAndSend();
        }
    }

    protected String createAndSend() {
        try {
            setSender();
            current.created(getLoginPerson());
            getFacade().create(current);
            current.setSentAt(new Date());
            current.modified(getLoginPerson());
            getFacade().edit(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("InternalMessageEntitySent"));
            postSend();
            return getRedirectLink();
        } catch (Exception e) {
            e.printStackTrace();
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    protected String updateAndSend() {
        try {
            if (current.getSentAt() != null) {
                JsfUtil.addErrorMessage(new Exception("Cannot edit sent message."), "Cannot edit sent message.");
                return null;
            }
            setSender();
            current.setSentAt(new Date());
            current.modified(getLoginPerson());
            getFacade().edit(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("InternalMessageEntitySent"));
            postSend();
            return getRedirectLink();
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    protected void postSend() {
        System.out.println("Usermessage: in postSend()");
        InternalMessageEntity message = current;
        ArrayList<SystemUserEntity> usersNeedMsgInstances = new ArrayList<SystemUserEntity>();

        //update messages recieved
        if (message.getDepartmentRecipients() != null) {
            for (DepartmentEntity d : message.getDepartmentRecipients()) {
                d.getMessagesReceived().add(message);
                departmentBean.edit(d);

                usersNeedMsgInstances.addAll(d.getEmployees());
            }
        }


        if (message.getRecipients() != null) {
            usersNeedMsgInstances.addAll(message.getRecipients());
            for (SystemUserEntity user : message.getRecipients()) {
                user.getMessagesReceived().add(message);
                userBean.edit(user);
            }
        }

        //create msg instances for each user
        for (SystemUserEntity user : usersNeedMsgInstances) {
            InternalMessageReceivedEntity msgInstance = new InternalMessageReceivedEntity();
            msgInstance.setReceiver(user);
            msgInstance.setMsg(message);
            ejbFacade.createInternalMessageReceivedEntity(msgInstance);

            user.getMessagesReceivedInstances().add(msgInstance);
            userBean.edit(user);
        }

        //update messages sent
        SystemUserEntity sender = message.getSender();
        sender.getMessagesSent().add(message);
        userBean.edit(sender);

        discardAndRediret();        
    }

    public void markAsRead() {
        InternalMessageReceivedEntity msgInstance = msgToUserInstance.get(current);
        if (!msgInstance.read()) {
            msgInstance.setOpenedAt(new Date());
            ejbFacade.editInternalMessageReceivedEntity(msgInstance);
        }
    }

    public String markAsUnRead() {
        InternalMessageReceivedEntity msgInstance = msgToUserInstance.get(current);
        if (msgInstance.read()) {
            msgInstance.setOpenedAt(null);
            ejbFacade.editInternalMessageReceivedEntity(msgInstance);
            return discardAndRediret();
        }
        return getRedirectLink();
    }

    public boolean isRead() {
        InternalMessageReceivedEntity msgInstance = msgToUserInstance.get(current);
        return msgInstance.read();
    }

    public String getfirstReadAt() {
        InternalMessageReceivedEntity msgInstance = msgToUserInstance.get(current);
        return msgInstance.getOpenedAt().toString();
    }

    public void discard() {
        //reset current
        current = new InternalMessageEntity();
        selectedMessage = current;
        System.out.println("draft discarded");
        tabIndex=1;
    }

    public String discardAndRediret() {
        //reset current
        System.out.println("Usermessage: discard and redirect");
        discard();
        populateInbox();
        tabIndex=1;
        return getRedirectLink();
    }

    public String reply() {
        current = new InternalMessageEntity();
        ArrayList<SystemUserEntity> to = new ArrayList<SystemUserEntity>();
        to.add(selectedMessage.getSender());
        current.setRecipients(to);
        current.setTitle("Re: " + selectedMessage.getTitle());
        return createOrUpdateUserMessage();
    }

    public String forward() {
        current = new InternalMessageEntity();
        current.setTitle("Fwd: " + selectedMessage.getTitle());
        current.setBody("Orignal message: " + selectedMessage.getBody());
        return createOrUpdateUserMessage();
    }

    protected void setSender() {
        if (current.getSender() == null || current.getSender().getId() == null || current.getSender().getId() < 0) {
            current.setSender(userManagedBean.getCurrentUser());
        }
    }

    @FacesConverter(forClass = InternalMessageEntity.class)
    public static class UserMessageControllerConverter implements Converter {

        public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
            UserMessageController controller = (UserMessageController) facesContext.getApplication().getELResolver().
                    getValue(facesContext.getELContext(), null, "UserMessageController");
            return controller.ejbFacade.find(getKey(value));
        }

        java.lang.Long getKey(String value) {
            java.lang.Long key;
            key = Long.valueOf(value);
            return key;
        }

        String getStringKey(java.lang.Long value) {
            StringBuffer sb = new StringBuffer();
            sb.append(value);
            return sb.toString();
        }

        public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
            if (object == null) {
                return null;
            }
            if (object instanceof InternalMessageEntity) {
                InternalMessageEntity o = (InternalMessageEntity) object;
                return getStringKey(o.getId());
            } else {
                throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + UserMessageController.class.getName());
            }
        }
    }

    public boolean isDisplayRecipients() {
        boolean display = false;
        if (current != null) {
            display = current.getMessageType() == MessageType.UserMessage || current.getMessageType() == MessageType.SystemMessage;
        }
        return display;
    }

    public boolean isDisplayDepartmentRecipients() {
        boolean display = false;
        if (current != null) {
            display = current.getMessageType() == MessageType.Announcement || current.getMessageType() == MessageType.SystemMessage;
        }
        return display;
    }

    public MessageController getUserManagedBean() {
        return userManagedBean;
    }

    public void setUserManagedBean(MessageController userManagedBean) {
        this.userManagedBean = userManagedBean;
    }

    public SelectItem[] getItemsAvailableSelectMany() {
        return JsfUtil.getSelectItems(ejbFacade.findAll(), false);
    }

    public SelectItem[] getItemsAvailableSelectOne() {
        return JsfUtil.getSelectItems(ejbFacade.findAll(), true);
    }

    public MessageType[] getMessageTypes() {
        return MessageType.values();
    }

    public InternalMessageEntity getMessageTobeDeleted() {
        return messageTobeDeleted;
    }

    public void setMessageTobeDeleted(InternalMessageEntity messageTobeDeleted) {
        System.out.println("setting message to be deleted: " + messageTobeDeleted);
        this.messageTobeDeleted = messageTobeDeleted;
        performDestroy(this.messageTobeDeleted);
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }

    public List<InternalMessageEntity> getMsg() {
        return msg;
    }

    public void setMsg(ArrayList<InternalMessageEntity> msg) {
        this.msg = msg;
    }

    public InternalMessageEntity getSelectedMessage() {
        return selectedMessage;
    }

    public void setSelectedMessage(InternalMessageEntity selectedMessage) {
        this.selectedMessage = selectedMessage;
    }

    public InternalMessageEntity getCurrent() {
        return current;
    }

    public void setCurrent(InternalMessageEntity current) {
        this.current = current;
    }

    public DepartmentEntityFacade getDepartmentBean() {
        return departmentBean;
    }

    public void setDepartmentBean(DepartmentEntityFacade departmentBean) {
        this.departmentBean = departmentBean;
    }

    public InternalMessageEntityFacade getEjbFacade() {
        return ejbFacade;
    }

    public void setEjbFacade(InternalMessageEntityFacade ejbFacade) {
        this.ejbFacade = ejbFacade;
    }

    public SystemUserEntityFacade getUserBean() {
        return userBean;
    }

    public void setUserBean(SystemUserEntityFacade userBean) {
        this.userBean = userBean;
    }

    protected InternalMessageEntityFacade getFacade() {
        return ejbFacade;
    }

    public String getRedirectLink() {
        return redirectLink;
    }

    public void setRedirectLink(String redirectLink) {
        this.redirectLink = redirectLink;
    }

    public String getViewLink() {
        return viewLink;
    }

    public void setViewLink(String viewLink) {
        this.viewLink = viewLink;
    }

    public boolean isForInbox() {
        return (msgToUserInstance != null && !msgToUserInstance.isEmpty());
    }

    public int getTotalUnread() {
        return totalUnread;
    }

    public void setTotalUnread(int totalUnread) {
        this.totalUnread = totalUnread;
    }

    public int getTabIndex() {
        return tabIndex;
    }

    public void setTabIndex(int tabIndex) {
        this.tabIndex = tabIndex;
    }
    
}
